home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
batchut
/
rbsetnv1.zip
/
COMSUB.C
< prev
next >
Wrap
Text File
|
1991-01-03
|
7KB
|
244 lines
/*
* comsub.c - routines to perform command substitution and environment variable
* parsing and expansion
*
* Author: R. Brittain 4/11/90
* This code placed in the public domain
*
*/
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "comsub.h"
int rebuild_argv(int *argc, char ***argv)
{
/*
* Build a new argv array, by iteratively performing backquote expansion
* and environment variable expansion until no more is possible.
* We always replace argv[] at least once, because the routine terminates it
* with an extra null, which is useful later for exec()ing.
* Returns the number of substitutions performed
*/
int i, count = 0, subst;
count += expand_backquotes(argc, argv);
do {
subst = FALSE;
/* look for any argument beginning with BKQ or ENV */
for (i=0; i < *argc; i++) {
if (*(*argv)[i] == BKQ || *(*argv)[i] == ENV ) {
subst = TRUE;
break;
}
}
if (subst) count += expand_backquotes(argc, argv);
} while (subst);
return(count);
}
int expand_backquotes(int *argc, char ***argv)
{
/*
* Perform command substitution if any argument begins with BKQ (`)
* Perform environment variable expansion if an argument begins with ENV (%)
* Returns the number of substitutions performed
* This routine would be simpler if backquoted commands were always parsed
* as a single command line argument, but doing it here means we don't need
* to modify the startup code.
*/
char **base, *p, *result;
estring command = {NULL, NULL, 0, 80};
int i, j, status = 0;
FILE *fp;
MEMCHECK(base = (char **) malloc(sizeof(char **))) ;
*base = NULL;
for (i=0, j=0; i < *argc; i++) {
if (*(*argv)[i] == BKQ) {
/*
* first character is a BKQ - we have a request for command
* substitution so build command in an estring structure
*/
status++;
MEMCHECK( addstring(&command, (*argv)[i]+1, 0) );
if (*command.b == EXE) {
set_popen_exec();
command.b++;
} else {
set_popen_shell();
}
/*
* if this argument ends with a second BKQ, remove it
* otherwise, scan forward for an argument terminated by BKQ,
* appending to command as we go
*/
if (*(p = endptr(command.b)-1) == BKQ) {
*p = '\0';
} else {
do {
/* increment argument pointer and append to current command */
if ( i++ >= *argc) fatal("Unterminated command substitution",1);
/* we ran out of arguments before finding BKQ */
MEMCHECK(addstring(&command," ",1));
MEMCHECK(addstring(&command,(*argv)[i], 0));
} while (*(endptr((*argv)[i])-1) != BKQ);
/* now stomp on of the trailing backquote */
if (*(p = endptr(command.b)-1) == BKQ) *p = '\0';
}
/* perform variable substitution then run the command via popen */
command.b = expand_env(command.b);
if ((fp = popen(command.b, "r")) == NULL) {
fputs (command.b, stderr);
fatal(": popen failed: \n",1);
}
result = mfgets(fp);
pclose(fp);
/* now parse <result> for whitespace and treat as new arguments */
p = strtok(result," \t");
while (p != NULL) {
MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
MEMCHECK(base[j++] = strdup(p)) ;
base[j] = (char *)NULL;
p = strtok(NULL," \t");
}
} else if (*(*argv)[i] == ENV) {
/* we have a request for environment substitution */
status++;
result = expand_env((*argv)[i]);
/* now parse <result> for whitespace and treat as new arguments */
p = strtok(result," \t");
while (p != NULL) {
MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
MEMCHECK(base[j++] = strdup(p)) ;
base[j] = (char *)NULL;
p = strtok(NULL," \t");
}
} else {
/* grab one more pointer, add to base array, and copy this argument */
MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
base[j++] = (*argv)[i];
base[j] = (char *)NULL;
}
}
*argv = base;
*argc = j;
return(status);
}
char *endptr(p)
char *p;
{
while (*p) p++;
return p;
}
char *mfgets (FILE *stream)
{
/*
* Suck in the entire file, replacing newlines by spaces
* and allocating memory as needed
*/
estring contents = {NULL, NULL, 0, 132};
char line[132];
if (feof(stream)) return NULL;
while (fgets(line,sizeof(line),stream) != NULL) {
if (*(endptr(line)-1) == '\n') *(endptr(line)-1) = ' ';
addstring(&contents,line,strlen(line));
}
return(contents.b);
}
char *expand_env(char *s)
{
/*
* Scan string s for '%' (or ENV) and expand environment variables as found
* Return a pointer to the expanded string (which may be the same as the input)
* The input string is left intact
*/
char *r;
estring result = {NULL, NULL, 0, 128};
estring var = {NULL, NULL, 0, 64};
result.p = result.b;
if (strchr(s,ENV) == NULL) {
/*
* nothing to do
*/
return(s);
} else {
/*
* we have some vars to substitute - parse into words by whitespace
* and examine each one
*/
while (*s) {
if (*s == ENV) {
/* some work to do */
if (*(++s) == ENV) {
/* double ENV */
MEMCHECK(addstring(&result, s++, 1));
} else {
/* look for next whitespace or ENV */
var.b = var.p;
while (*s && *s != ENV && !isspace(*s)) {
addstring(&var, s++, 1);
}
/* copy over the variable value, if non null */
if ((r = getenv(strupr(var.b))) != NULL)
MEMCHECK(addstring(&result,r,strlen(r)));
/* examine how the var name was terminated */
if (*s == ENV && isspace(*(s+1))) {
/* redundant trailing ENV - skip over */
s++;
}
}
} else {
/* just copy characters */
MEMCHECK(addstring(&result, s++, 1));
}
}
return(result.b);
}
}
char *addstring(estring *es, char *add, int count)
{
/*
* Add <count> characters from string <add> to estring <es>
* <es> is extended automatically as needed
* Returns a pointer to the start of the string (NULL if an expansion failed)
* If the count is zero, then it is taken to be strlen(add) by default
*/
if (count == 0) count = strlen(add);
if (es->p - es->b + count >= es->len) {
if (es->p != NULL) {
/* we are expanding */
*es->p = '\0';
es->b = (char *)realloc(es->b, es->len + max(es->inc, count+1));
if (es->b == (char *)NULL) return (NULL);
es->p = endptr(es->b);
es->len += es->inc;
} else {
/* we are making initial allocation */
es->p = es->b = (char *)calloc(max(es->inc,count+1), 1);
if (es->b == (char *)NULL) return (NULL);
es->len = es->inc;
}
}
strncpy(es->p, add, count);
es->p += count;
*es->p = '\0';
return(es->b);
}